﻿using Admin.Application.DynamicApi.System.Auth.Dto;
using Admin.Application.DynamicApi.System.Menu;
using Admin.Database.Enums;
using Admin.Database.Model;
using Framework.Core;
using Framework.Core.CustomException;
using Framework.DI;
using Framework.DynamicApiController;
using Framework.SqlSugar.Repository;
using Framework.Util.Encryption;
using Framework.WebApi.Authentication;
using Framework.WebApi.Options;
using Lazy.Captcha.Core;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using NewLife;
using NewLife.Log;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Yitter.IdGenerator;

namespace Admin.Application.DynamicApi.System.Auth
{
	[Service]
	public class SysAuthService
	{
		private readonly ICaptcha _captcha;
		private readonly SqlSugarRepository<SysUser> _sysUserRep;
		private readonly ILogger<SysAuthService> _logger;
		private readonly UserManager _userManager;
		private readonly SysMenuService _sysMenuService;

		public SysAuthService(SqlSugarRepository<SysUser> sysUserRep, ILogger<SysAuthService> logger,
			SysMenuService sysMenuService,UserManager userManager, ICaptcha captcha)
        {
            _captcha = captcha;
			_sysUserRep = sysUserRep;
			_logger = logger;
            _userManager = userManager;
			_sysMenuService = sysMenuService;
		}

		/// <summary>
		/// 获取验证码 🔖
		/// </summary>
		/// <returns></returns>
		[AllowAnonymous]
		[DisplayName("获取验证码")]
		public dynamic GetCaptcha()
		{
			var codeId = YitIdHelper.NextId().ToString();
			var captcha = _captcha.Generate(codeId);
			var expirySeconds = App.GetOptions<CaptchaOptions>()?.ExpirySeconds ?? 60;
			return new { Id = codeId, Img = captcha.Base64, ExpirySeconds = expirySeconds };
		}

		/// <summary>
		/// 账号密码登录 🔖
		/// </summary>
		/// <param name="input"></param>
		/// <remarks>用户名/密码：superadmin/123456</remarks>
		/// <returns></returns>
		[AllowAnonymous]
		[DisplayName("账号密码登录")]
		public virtual async Task<LoginOutput> Login([Required] LoginInput input)
		{
			//// 判断密码错误次数（缓存30分钟）
			//var keyPasswordErrorTimes = $"{CacheConst.KeyPasswordErrorTimes}{input.Account}";
			//var passwordErrorTimes = _sysCacheService.Get<int>(keyPasswordErrorTimes);
			//var passwordMaxErrorTimes = await _sysConfigService.GetConfigValue<int>(ConfigConst.SysPasswordMaxErrorTimes);
			//// 若未配置或误配置为0、负数, 则默认密码错误次数最大为10次
			//if (passwordMaxErrorTimes < 1) passwordMaxErrorTimes = 10;
			//if (passwordErrorTimes > passwordMaxErrorTimes) throw Oops.Oh(ErrorCodeEnum.D1027);

			// 判断是否开启验证码，其校验验证码
			if (!_captcha.Validate(input.CodeId.ToString(), input.Code)) throw new CustomException("验证码错误");

			// 获取登录租户和用户
			var user = await GetLoginUser( input.Account);

			// 账号是否被冻结
			if (user.Status == StatusEnum.Disable) throw new CustomException("账号已冻结");

			// 验证密码
			VerifyPassword(input.Password,  user);

			return await CreateToken(user);
		}

		/// <summary>
		/// 账号密码登录 🔖
		/// </summary>
		/// <param name="input"></param>
		/// <remarks>用户名/密码：superadmin/123456</remarks>
		/// <returns></returns>
		[AllowAnonymous]
		[DisplayName("账号密码登录")]
		public virtual async Task<LoginOutput> AutoLogin()
		{

			// 获取登录租户和用户
			var user = await GetLoginUser("admin");

			return await CreateToken(user);
		}

		/// <summary>
		/// 获取登录租户和用户
		/// </summary>
		/// <param name="tenantId"></param>
		/// <param name="account"></param>
		/// <param name="phone"></param>
		/// <returns></returns>
		[NonAction]
		public async Task<SysUser> GetLoginUser(string account = null)
		{
			// 账号是否存在
			var user = await _sysUserRep.AsQueryable().Includes(u => u.SysOrg).ClearFilter()
				.WhereIF(!string.IsNullOrWhiteSpace(account), u => u.Account.Equals(account)).FirstAsync();
			_ = user ?? throw new CustomException("账号不存在");
			
			return user;
		}

		/// <summary>
		/// 验证用户密码
		/// </summary>
		/// <param name="password"></param>
		/// <param name="keyPasswordErrorTimes"></param>
		/// <param name="passwordErrorTimes"></param>
		/// <param name="user"></param>
		private void VerifyPassword(string password,  SysUser user)
		{
			try
			{
				// 验证用户密码
				if (user.Password.Equals(MD5Encryption.Encrypt(password,true, false))) return;
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, "密码验证错误");
			}
			
			throw new CustomException("密码不正确");
		}

		/// <summary>
		/// 生成Token令牌 🔖
		/// </summary>
		/// <param name="user"></param>
		/// <returns></returns>
		[NonAction]
		internal virtual async Task<LoginOutput> CreateToken(SysUser user)
		{
			JWTSettingsOptions JwtSettings = App.GetConfig<JWTSettingsOptions>("JwtSettings");
			
			// 生成Token令牌
			var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
			{
				{ ClaimConst.UserId, user.Id },
				{ ClaimConst.Account, user.Account },
				{ ClaimConst.Name, user.Name },
				{ ClaimConst.OrgId, user.OrgId },
				{ ClaimConst.OrgName, user.SysOrg?.Name },
			}, JwtSettings.ExpiredTime);

			// 生成刷新Token令牌
			int refreshTokenExpire = (int)JwtSettings.RefreshTokenExpiredTime;
			var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire);

			// 设置响应报文头
			//_httpContextAccessor.HttpContext.SetTokensOfResponseHeaders(accessToken, refreshToken);

			// 更新用户登录信息
			//user.LastLoginIp = _httpContextAccessor.HttpContext.GetRemoteIpAddressToIPv4(true);
			//(user.LastLoginAddress, double? longitude, double? latitude) = CommonUtil.GetIpAddress(user.LastLoginIp);
			//user.LastLoginTime = DateTime.Now;
			//user.LastLoginDevice = CommonUtil.GetClientDeviceInfo(_httpContextAccessor.HttpContext?.Request?.Headers?.UserAgent);
			//await _sysUserRep.AsUpdateable(user).UpdateColumns(u => new
			//{
			//	u.LastLoginIp,
			//	u.LastLoginAddress,
			//	u.LastLoginTime,
			//	u.LastLoginDevice,
			//}).ExecuteCommandAsync();

			var payload = new
			{
				Entity = user,
				Output = new LoginOutput
				{
					AccessToken = accessToken,
					RefreshToken = refreshToken
				}
			};

			//// 发布系统用户操作事件
			//await _eventPublisher.PublishAsync(SysUserEventTypeEnum.Login, payload);
			return payload.Output;
		}

		/// <summary>
		/// 获取登录账号 🔖
		/// </summary>
		/// <returns></returns>
		[DisplayName("获取登录账号")]
		public virtual async Task<LoginUserOutput> GetUserInfo()
		{
			long UserId;
			try 
			{
				UserId = _userManager.UserId;
			}
			catch (Exception)
			{
				return null;
			}

			var user = await _sysUserRep.AsQueryable().ClearFilter().FirstAsync(u => u.Id == UserId) ?? throw new CustomException(401,"非法操作，未登录");
			// 获取机构
			var org = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysOrg>>().GetFirstAsync(u => u.Id == user.OrgId);

			// 获取按钮集合
			var buttons = await _sysMenuService.GetOwnBtnPermList();
			// 获取角色集合
			var roleIds = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysUserRole>>().AsQueryable()
				.Where(u => u.UserId == user.Id).Select(u => u.RoleId).ToListAsync();

			return new LoginUserOutput
			{
				Id = user.Id,
				Account = user.Account,
				Name = user.Name,
				OrgId = user.OrgId,
				OrgName = org?.Name,
				Buttons = buttons,
				RoleIds = roleIds,
			};
		}

		/// <summary>
		/// 获取刷新Token 🔖
		/// </summary>
		/// <param name="accessToken"></param>
		/// <returns></returns>
		[DisplayName("获取刷新Token")]
		public virtual string GetRefreshToken([FromQuery] string accessToken)
		{
			JWTSettingsOptions JwtSettings = App.GetConfig<JWTSettingsOptions>("JwtSettings");

			return JWTEncryption.GenerateRefreshToken(accessToken, (int)JwtSettings.RefreshTokenExpiredTime);
		}
	}
}
